home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / HDX_BACK / HDX302.ST / MARKBAD.C < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-09  |  38.3 KB  |  1,342 lines

  1. /* markbad.c */
  2.  
  3. /* 18-Apr-88  ml.    implement delete of trashed subdirectory with        */
  4. /*            recovering of files.                                           */
  5. /* 16-Mar-88  ml.    split assist.c into this and zero.c.                   */
  6. /* 15-Mar-88  ml.    allow user to determine destiny of trashed files.      */
  7. /* 16-Oct-87  ml.    fixed some bugs.                                       */
  8. /* 26-Oct-87  ml.    rewrote markbad, readrange, fixbadcls (everything).    */
  9. /* 28-Oct-87  ml.    modified markbad to mark fats and root dir also.    */
  10. /* 11-Dec-87  ml.    added BSL concept to markbad() and zero().            */
  11. /* 13-Oct-88  J.Ye    change and add codes for big partition.                */
  12. /* 18-Agu-89  J.Ye    change codes to support header size over 256MB        */
  13.  
  14. #include "obdefs.h"
  15. #include "gemdefs.h"
  16. #include "osbind.h"
  17. #include "mydefs.h"
  18. #include "part.h"
  19. #include "bsl.h"
  20. #include "getstart.h"
  21. #include "hdx.h"
  22. #include "addr.h"
  23.  
  24. extern long gbslsiz();
  25. extern long nument();
  26. extern long cntbad();
  27. extern int *fatck();
  28. extern GSINFO *getstart();
  29. extern long bslsiz;
  30. extern BYTE *bsl;
  31. extern SECTOR badbuf[];        /* bad sectors buffer */
  32. extern long ratio;
  33.  
  34. UWORD ndirs;    /* total number of root directory entries */
  35. UWORD sectdir;    /* number of sectors root directory entries take up */
  36. UWORD clusiz;    /* number of bytes per cluster */
  37. SECTOR strootdir;    /* starting sector number of root directory */
  38. int endofdir;        /* TRUE: reaches end of directory */
  39.  
  40. int emptyorph=0;    /* an empty orphan list */
  41. GSINFO    *finfo;        /* file information from getstart() */
  42.  
  43. extern int gl_wchar;    /* width of system font (pixels) */
  44. char pname[260];    /* full path name of a file */
  45. char dpname[260];    /* full path name of a file to be displayed */
  46. char sectbuf[10];
  47. char clusbuf[10];
  48. long sysize;        /* system available memory */
  49.  
  50.  
  51. /*
  52.  * Mark bad sectors on the logical dev
  53.  *
  54.  */
  55.  
  56. markbad(ldev)
  57. int ldev;
  58. {
  59.     SECTOR fat0, fat1, data, sect2read, dummy = 0L;
  60.     long nsects;
  61.     UWORD fatsiz, w1, w2;
  62.     UWORD pbad, bps;
  63.     char bs[512], foundbuf[10], markdbuf[10];
  64.     BOOT *boot;
  65.     int pdev, ret, nbad;
  66.  
  67.     
  68.     pdev = ldev;
  69.     log2phys(&pdev, &dummy);
  70.     
  71.     /* Allocate memory for BSL and try to read it */ 
  72.     bsl = 0L;
  73.     if ((bslsiz = gbslsiz(pdev)) > 0L) {
  74.         if ((bsl = (BYTE *)mymalloc((int)bslsiz << 9)) <= 0)
  75.             return err(nomemory);
  76.             
  77.         if ((dummy = rdbsl(pdev)) != OK) {
  78.             free(bsl);
  79.             if (dummy == INVALID)
  80.                 err(cruptbsl);
  81.             return ERROR;
  82.         }
  83.     } else if (bslsiz < 0L){
  84.     if (bslsiz == ERROR)
  85.         err(rootread);
  86.     return ERROR;
  87.     }
  88.  
  89.     /*
  90.      * Read boot sector and extract volume information.
  91.      */
  92.     if ((ret = rdsects(ldev, 1, bs, (SECTOR)0)) != 0) {
  93.         free(bsl);
  94.         if (tsterr(ret) != OK)
  95.             err(bootread);
  96.         return ERROR;
  97.     }
  98.  
  99.     boot = (BOOT *)bs;
  100.      
  101.     gw((UWORD *)&boot->b_ndirs[0], &ndirs);
  102.     gw((UWORD *)&boot->b_spf[0], &fatsiz);
  103.     gw((UWORD *)&boot->b_res[0], &w1);
  104.     gw((UWORD *)&boot->b_nsects[0], &w2);
  105.     gw((UWORD *)&boot->b_bps[0], &bps);
  106.     ratio = bps / BPS;
  107.     fatsiz = fatsiz * ratio;
  108.     clusiz = (UWORD)boot->b_spc * bps;
  109.     fat0 = (SECTOR)w1 * ratio;
  110.     fat1 = fat0 + (SECTOR)fatsiz;
  111.     strootdir = fat1 + fatsiz;
  112.     sectdir = (ndirs * BPDIR) / BPS;
  113.     data = (SECTOR)(strootdir + sectdir);
  114.     nsects = (SECTOR)w2 * ratio;
  115.     sect2read = nsects - data;
  116.  
  117.     /* Marking bad */
  118.     if ((nbad = readfix(ldev, data, fat0, fatsiz, sect2read, &pbad)) < 0) {
  119.         if (bsl > 0) free(bsl);
  120.         return ERROR;
  121.     }
  122.  
  123.     /* Bad sectors found, BSL modified.  Write it back. */
  124.     if (nbad) {
  125.         if (bslsiz)
  126.             if (wrbsl(pdev) != OK) {
  127.                 free(bsl);
  128.                 return ERROR;
  129.             }
  130.     }
  131.     if (bsl > 0) free(bsl);        
  132.     
  133.     /* Display result of markbad */
  134.     itoa(nbad, foundbuf);
  135.     itoa(pbad, markdbuf);
  136.     (lmrkdone[BADFOUND].ob_spec)->te_ptext = foundbuf;
  137.     (lmrkdone[BADMARKD].ob_spec)->te_ptext = markdbuf;
  138.     lmrkdone[LMDONE].ob_state = NORMAL;
  139.     erasemsg();
  140.     execform(lmrkdone);
  141.     return OK;
  142. }
  143.  
  144.  
  145.   
  146. /* 
  147.  * Critical Error Handler:
  148.  *    Always return -1L
  149.  *
  150.  */
  151. long
  152. crerr()
  153. {
  154.     return -1L;
  155. }
  156.  
  157.  
  158.  
  159. /*
  160.  * Read range of sectors,
  161.  * record bad ones in the vector,
  162.  * add bad sectors found to the BSL,
  163.  * mark bad sectors in the FATs,
  164.  * return number of bad ones.
  165.  *
  166.  */
  167. readfix(ldev, data, fat0, fatsiz, sect2read, pbad)
  168. int ldev;        /* logical device to read from */
  169. SECTOR data;        /* LSN of first sector of data clusters */
  170. SECTOR fat0;        /* LSN of first sector of FAT 0 */
  171. UWORD fatsiz;        /* size of FAT in sectors */
  172. SECTOR sect2read;    /* number of sectors to read */
  173. UWORD  *pbad;        /* ptr to # previously recorded bad sector */
  174. {
  175.     int nbad=0, full=0, ret;
  176.     int pdev;        /* physical device number */
  177.     SECTOR pstart;    /* physical starting block# of partition */
  178.     SECTOR pdata;    /* physical starting block# of data clusters */
  179.     SECTOR temp;    /* physical starting block# of data clusters */
  180.     SECTOR *pbadbuf;
  181.     SECTOR *knownbad();
  182.     SECTOR cnt, cnt1;
  183.     UWORD newbad;
  184.     extern SECTOR logstart();
  185.     char *rbuf = 0L;        /* read buffer */
  186.     long dummy = 0L;
  187.  
  188.     pdev = ldev;
  189.     log2phys(&pdev, &dummy);
  190.     pstart = logstart(ldev);
  191.  
  192.         
  193.     /* if there's a bsl, find # of previously found bad sector */
  194.     *pbad = 0;
  195.     pbadbuf = 0L;
  196.     pdata = pstart + data;
  197.     temp = pdata;
  198.     if (bslsiz)    {
  199.         if ((pbadbuf = knownbad(pdata, sect2read, pbad)) < 0L)
  200.             goto readend;
  201.     }
  202.  
  203.     /* Allocate memory for read buffer */
  204.     if ((sysize = Malloc(-1L)) <= 0) {
  205.         ret = err(nomemory);
  206.         goto readend;
  207.     }
  208.     if ((sysize/512L) > MAXBUFSECT)    /* the max # of sector for hread() is 254 */
  209.         sysize = MAXBUFSECT * 512; 
  210.  
  211.     if ((rbuf = (char *)Malloc(sysize)) <= 0) {
  212.         ret = err(nomemory);
  213.         goto readend;
  214.     }
  215.  
  216.     /*
  217.      * Read lots of sectors, MAXSECTS sectors at a time;
  218.      * if an error happens, then probe individual sectors
  219.      * in the lump of MAXSECTS that failed.
  220.      */
  221.  
  222.     newbad = 0;
  223.     /* convert the bytes to the sectors */
  224.     sysize /= 512;
  225.     while (sect2read > 0) {
  226.         if (sect2read > sysize)
  227.             cnt = sysize;
  228.         else
  229.             cnt = sect2read;
  230.         if ((ret = rdsects(pdev, (UWORD)cnt, rbuf, pdata)) != 0) {
  231.             if (tsterr(ret) == OK) {
  232.                 ret = ERROR;
  233.                 goto readend;
  234.             }
  235.             cnt1 = cnt;
  236.             while (cnt1) {
  237.                 if ((ret = rdsects(pdev, 1, rbuf, pdata)) != 0) {
  238.                     if (tsterr(ret) == OK) {
  239.                         ret = ERROR;
  240.                         goto readend;
  241.                     }
  242.                 if (*pbad)    {
  243.                     /* if so, see if bad sector found uis one of them */
  244.                     if (!fl(pdata, *pbad, pbadbuf)) {
  245.                         /* if it is not, it's a newly found one */
  246.                         newbad++;
  247.                     }
  248.                 } else {
  249.                     newbad++;
  250.                 }
  251.                 badbuf[nbad++] = pdata;
  252.  
  253.                 /* badbuf is filled */
  254.                 if (nbad == WARNBADSECTS) {
  255.                     if (rbuf > 0) Mfree(rbuf);    
  256.                     rbuf = 0L;
  257.                     if (bslsiz && !full)    /* USER list is not full yet */
  258.                         /* try to add bad sectors found to BSL */
  259.                         if ((ret = addbsl(pdev, USER, nbad)) < 0) {
  260.                             if (ret == USRFULL)
  261.                                 full = 1;
  262.                             else {
  263.                                 ret = ERROR;
  264.                                 goto readend;
  265.                             }
  266.                         } else if (ret > 0) {
  267.                             if (wrbsl(pdev) != 0) {
  268.                             ret = ERROR;
  269.                             goto readend;
  270.                             }
  271.                             }
  272.                 
  273.                     /* mark the bad sectors in the FATs */
  274.                     if ((ret = fixbadcls(ldev, fat0, fatsiz, 
  275.                             data, nbad)) < 0) {
  276.                         goto readend;
  277.                     }
  278.                     nbad = 0;    /* reinit bad sectors count to 0 */
  279.  
  280.                     /* Allocate memory for read buffer */
  281.                     if ((sysize = Malloc(-1L)) <= 0) {
  282.                         ret = err(nomemory);
  283.                         goto readend;
  284.                     }
  285.                     if ((rbuf = (char *)Malloc(sysize)) <= 0) {
  286.                         ret = err(nomemory);
  287.                         goto readend;
  288.                     }
  289.                     sysize /= 512;
  290.                 }
  291.                                         
  292.             }
  293.             cnt1--;
  294.             pdata++;
  295.         }
  296.     } else {
  297.         pdata += cnt;
  298.     }
  299.         sect2read -= cnt;
  300.     }
  301.     
  302.     if (rbuf > 0) Mfree(rbuf);    
  303.     rbuf = 0;
  304.  
  305.     if (nbad) {    /* bad sectors found but not recorded in BSL or FATs */
  306.         if (bslsiz && !full)    /* USER list is not full yet */
  307.             /* try to add bad sectors found to BSL */
  308.             if ((ret = addbsl(pdev, USER, nbad)) < 0) {
  309.                 if (ret == USRFULL)
  310.                     full = 1;
  311.                 else {
  312.                     ret = ERROR;
  313.                     goto readend;
  314.                 }
  315.             } else if (ret > 0) {
  316.         if (wrbsl(pdev) != 0) {
  317.             ret = ERROR;
  318.             goto readend;
  319.         }
  320.         }                
  321.         
  322.         /* mark the bad sectors in the FATs in terms of clusters */
  323.         if ((ret = fixbadcls(ldev, fat0, fatsiz, data, nbad)) < 0) {
  324.         goto readend;
  325.         }
  326.     }
  327.     ret = newbad;
  328.     
  329. readend:
  330.     if (rbuf > 0) Mfree(rbuf);    
  331.     if (pbadbuf > 0) Mfree(rbuf);
  332.     return (ret);
  333. }
  334.  
  335.  
  336. /*
  337.  * Knownbad() - build a list of bad sectors that have been recorded
  338.  *            in the BSL within the range provided.
  339.  *
  340.  * Assumes:
  341.  *    BSL exists and has already been read into memory.
  342.  *
  343.  * Returns:
  344.  *    Pointer to a list of bad sectors that have been recorded in the
  345.  * BSL within the range provided, if there is any, and # of elements in 
  346.  * the list.
  347.  *
  348.  */
  349. SECTOR*
  350. knownbad(start, numsect, nbad)
  351. SECTOR    start;        /* starting sector of range */
  352. SECTOR    numsect;    /* # sectors within the range */
  353. UWORD    *nbad;        /* # elements in the list returned */
  354. {
  355.     extern long get3bytes();
  356.     long totbad, i;
  357.     SECTOR end, curr;
  358.     SECTOR *pbadbuf, *bufptr, *ret;
  359.     UWORD cnt;
  360.     char *bslptr, *first;
  361.     
  362.     ret = 0L;            /* no buffer allocated yet */
  363.     *nbad = cnt = 0;        /* no recorded bad sectors found yet */
  364.     
  365.     totbad = nument(MEDIA);    /* num entries in bsl */
  366.     sortbsl(totbad);        /* sort the bsl */
  367.     end = start + numsect;    /* end of range of sectors to be searched */
  368.     
  369.     bslptr = bsl + BPE*RENT;
  370.     for (i = 0L; i < totbad; i++, bslptr += BPE) {
  371.         if ((curr = get3bytes(bslptr)) >= end) {
  372.         break;
  373.     } else if (curr >= start) {
  374.         if (!cnt)
  375.         first = bslptr;
  376.         cnt++;
  377.     }
  378.     }
  379.         
  380.     if (cnt) {
  381.     if ((pbadbuf = (SECTOR *)mymalloc(cnt << 2)) <= 0L) {
  382.         err(nomemory);
  383.         ret = -1L;
  384.         goto kend;
  385.     }
  386.     
  387.     *nbad = cnt;
  388.     bufptr = pbadbuf;
  389.     while (cnt) {
  390.         if ((curr = get3bytes(first)) < end && curr >= start) {
  391.         *bufptr++ = curr;
  392.         cnt--;
  393.         }
  394.         first += BPE;
  395.     }
  396.     ret = pbadbuf;
  397.     }
  398. kend:
  399.     return ret;
  400. }
  401.  
  402.  
  403.  
  404. /*
  405.  * Fixup bad sector entries in the FATs;
  406.  * suboptimal, since a FAT sector is read and two are
  407.  * written for EACH bad sector, even if there is
  408.  * more than one bad entry in a given FAT sector.
  409.  *
  410.  *
  411.  */
  412. fixbadcls(ldev, fat0, fatsiz, data, nbad)
  413. int ldev;        /* logical device */
  414. SECTOR fat0, data;
  415. UWORD fatsiz;
  416. int nbad;
  417. {
  418.     long numcl;
  419.     UWORD clno, nxtcl;
  420.     int i;
  421.     UWORD *buf;
  422.     SECTOR fat1;    /* physical starting sector# of 2nd FAT */
  423.     SECTOR pstart;    /* physical starting sector# of partition */
  424.     SECTOR badsect;    /* current bad sector */
  425.     extern SECTOR logstart();
  426.     extern LOGMAP logmap[];
  427.     int did=0, nmarked, ret, spc;
  428.     
  429.     
  430.     if((buf = (UWORD *)Malloc((long)fatsiz << 9)) <= 0)
  431.         return err(nomemory);
  432.     pstart = logstart(ldev);
  433.  
  434.     spc = 2*ratio;                    /* No, 2 spc */
  435.     numcl = (logmap[ldev-'C'].lm_siz - data) / spc;
  436.     fat1 = fat0 + fatsiz;
  437.             
  438.     if ((ret = rdsects(ldev, fatsiz, (char *)buf, fat0)) != 0) {
  439.         if (tsterr(ret) != OK)
  440.         err(fatread);
  441.     ret = ERROR;
  442.     goto fixend;
  443.     }
  444.     nmarked = 0;
  445.     for (i = 0; i < nbad; ++i) {
  446.     badsect = badbuf[i] - pstart;
  447.     if ((clno = (badsect - data)/spc) >= numcl)
  448.         continue;
  449.             
  450.        /* find out the next cluster number */
  451.        gw((UWORD *)(buf+clno+2), &nxtcl);
  452.             
  453.     /* part of file?? */
  454.        if (nxtcl != 0 && (nxtcl <= 0x7fff || nxtcl >= 0xfff8))    {
  455.            /* Yes, bummer */
  456.            if ((ret = partoffile(ldev, buf, fatsiz, badsect, clno, nxtcl))
  457.                    < 0)
  458.                goto fixend;
  459.            nmarked += ret;
  460.     } else {    /* just mark it bad */
  461.         /* Nope, ah ha, just mark it bad */
  462.         *(buf+clno+2) = 0xf7ff;    /* 0xfff7 in 8086-land */
  463.         nmarked++;
  464.     }
  465.  
  466.     /* write FAT0 and FAT1 */
  467.     if ((ret = wrsects(ldev, fatsiz, (char *)buf, fat0)) != 0 ||
  468.         (ret = wrsects(ldev, fatsiz, (char *)buf, fat1)) != 0)
  469.     {
  470.         if (tsterr(ret) != OK)
  471.             err(fatwrite);
  472.         ret = ERROR;
  473.         goto fixend;
  474.     }
  475.     }
  476.     ret = nmarked;
  477. fixend:
  478.     Mfree((long)buf);
  479.     return ret;
  480. }
  481.  
  482.  
  483. /*
  484.  *  Handle situations when bad sector found is currently allocated
  485.  *  to a file.
  486.  *
  487.  *    Options for user:
  488.  *        - Delete the victim file. (Lose all data in file.)
  489.  *          Bad sector will be marked in FATs.
  490.  *        - Skip over the cluster where the bad sector resides.
  491.  *          (Lose data in bad sector only.)  Need to patch up
  492.  *          FATs and root directory entry of file.  Bad sector
  493.  *          will be marked in FATs.
  494.  *        - Ignore the bad sector. Bad sector will stay unmarked
  495.  *          in FATs.
  496.  *
  497.  *    Input:
  498.  *        ldev - logical device.
  499.  *        fatimg - image of FAT table.
  500.  *        fatsiz - # clusters FAT occupies.
  501.  *        badsect - bad sector in question.
  502.  *        clno - cluster containing the bad sector.
  503.  *        nxtcl - next cluster in chain. (ie. cluster currently
  504.  *            pointed to by cluster with the bad sector.
  505.  *
  506.  *    Output:
  507.  *        ERROR - if something went wrong in the process.
  508.  *        1 - cluster in question is marked.  Image of FATs 'may'
  509.  *            be modified, depending on the option chosen by the
  510.  *            user.
  511.  *
  512.  *    Comments:
  513.  *        Things get pretty hairy when the bad sector is allocated
  514.  *    to a subdirectory file (ie. file that contains entries of other
  515.  *    files belonging to that subdirectory).  As of today (17-Mar-88),
  516.  *    no action (may be an alert) will be taken for victim subdirectory
  517.  *    files.
  518.  *        31-Mar-88 : started to add routines to take care of
  519.  *    trashed subdirectories.
  520.  *        11-Apr-88 : froze development of relinking trashed
  521.  *    subdirectories.  Will fix all known bugs and release first.
  522.  *        18-Apr-88 : started to implement recovering of files of
  523.  *    a trashed subdirectory.
  524.  *
  525.  */
  526. partoffile(ldev, fatimg, fatsiz, badsect, clno, nxtcl)
  527. int ldev;            /* logical device number */
  528. UWORD *fatimg;            /* FAT's image */
  529. UWORD fatsiz;        /* #sectors in FAT */
  530. SECTOR badsect;            /* sector which is bad */
  531. UWORD clno, nxtcl;    /* current cluster # and next cluster # */
  532. {
  533.     int *orphans;        /* list of orphans in FAT */
  534.     UWORD numorph;        /* number of orphans found in FAT */
  535.     FCB *dirent;        /* a directory entry */
  536.     int attribs;        /* file attributes */
  537.     int ret;            /* return code */
  538.     int tail;            /* num pixels path name exceeds box's width */
  539.     int sub;            /* TRUE: file in process is a subdirectory */
  540.     int i;            /* index */
  541.     
  542.     ret = OK;    /* assume everything is OK to start with */
  543.     /* Check integrity of FATs */
  544.     if ((orphans = fatck(ldev-'A')) <= 0L) {
  545.     switch (orphans) {
  546.         case FFATS:
  547.         ret = err(fatread);
  548.         goto leave;
  549.         case FROOT:
  550.         ret = err(dirread);
  551.         goto leave;
  552.         case FFAIL:
  553.         ret = err(nomemory);
  554.         goto leave;
  555.         case FAMBI:
  556.         ret = err(badfat);
  557.         goto leave;
  558.         default:
  559.         break;
  560.     }
  561.     }
  562.  
  563.     ltoa(badsect, sectbuf);    /* sector number of bad sector */
  564.     
  565.     /* Find what file bad sector is allocated to */
  566.     if ((finfo = getstart(orphans, clno+2, ldev-'A')) == GORPH) {
  567.         markorph[ORPHYES].ob_state = NORMAL;
  568.         markorph[ORPHNO].ob_state = NORMAL;
  569.         (markorph[ORPHSEC].ob_spec)->te_ptext = sectbuf;
  570.     itoa(clno+2, clusbuf);    /* +2: 2 unused entries at FAT */
  571.         (markorph[ORPHCLU].ob_spec)->te_ptext = clusbuf;
  572.         if (execform(markorph) == ORPHYES) {    /* want to mark orphan */
  573.             *(fatimg+clno+2) = 0xf7ff;        /* 0xfff7 in 8086-land */
  574.             ret = 1;
  575.         } else {        /* don't want to mark orphan */
  576.             ret = 0;
  577.         }
  578.         goto leave;
  579.     } else if (finfo == GFAIL) {
  580.     ret = err(nomemory);
  581.     goto leave;
  582.     } /* else if (finfo == GALLO || finfo == GOOFY
  583.          If these are ever returned, it's this
  584.          program's fault.
  585.       */
  586.  
  587.     if (!(finfo->gs_fpath[0])) {    /* 0: can't read subdirectory */
  588.         err(sdirread);
  589.         ret = 0;
  590.         goto leave;
  591.     }
  592.         
  593.     /* root of full path name of file */
  594.     pname[0] = ldev;
  595.     pname[1] = ':';
  596.     pname[2] = '\0';
  597.  
  598.     /* Have to display entire path name */
  599.     strcat(pname, finfo->gs_fpath);
  600.     
  601.     /* Is trashed file a subdirectory? */
  602.     /* How many characters will the path name exceed width of dialogue? */
  603.     if ((attribs = Fattrib(pname, 0, 0)) & FA_SUB) {
  604.     sub = TRUE;
  605.     tail = (strlen(finfo->gs_fpath)+2)*gl_wchar-lmrksub[BADSUB].ob_width;
  606.     } else {
  607.     sub = FALSE;
  608.     tail = (strlen(finfo->gs_fpath)+2)*gl_wchar-lmrkfile[BADFILE].ob_width;
  609.     } 
  610.     
  611.     /* Display path name, sector & cluster # concerned */    
  612.     if (tail <= 0) {    /* path name of file will fit in dialogue */
  613.     strcpy(dpname, pname);
  614.     } else {        /* path name of file is too long for dialogue */
  615.     dpname[0] = ldev;
  616.     dpname[1] = ':';
  617.     dpname[2] = '\0';
  618.         strcat(dpname, "\\...");
  619.         strcat(dpname, &(finfo->gs_fpath[tail/gl_wchar+4]));
  620.     }
  621.     
  622.     /* Set up dialogue with info of trashed file/subdirectory */
  623.     if (sub == TRUE) {        /* it's a subdirectory file */
  624.         ret = marksub(ldev, fatimg, fatsiz, clno);
  625.     } else {            /* it's a regular file */
  626.         ret = markfile(ldev, fatimg, fatsiz, clno, nxtcl);
  627.     }
  628. leave:
  629.     return (ret);
  630. }                
  631.  
  632.  
  633. /*
  634.  *  Marksub()
  635.  *    Put up dialogue informing which subdirectory is trashed, and
  636.  *  request action from user.
  637.  *
  638.  *  Input:
  639.  *    ldev  - logical device number. ('C' -> 'P')
  640.  *    fatimg  - image of FAT 0.
  641.  *    fatsiz - size of FAT in sectors.
  642.  *    clno - cluster which bad sector resides.
  643.  *
  644.  *  Return:
  645.  *    1 - if successful and cluster with bad sector is marked.
  646.  *    0 - if successful but nothing marked.
  647.  *    ERROR - can't read boot sector.
  648.  *
  649.  *  Comments:
  650.  *    15-Apr-88 ml.  If user choose to delete the subdirectory, all
  651.  *  files and subdirectories belonging to that subdirectory will also
  652.  *  be deleted.
  653.  *    18-Apr-88 ml.  Try to implement recovering files so that the user
  654.  *  only lose the directory structure.  All files and subdirectories
  655.  *  belonging to the 'trouble maker' now become temporary files under
  656.  *  the root directory.  So, number of files recovered depends on number
  657.  *  of empty slots remained in the root directory.
  658.  * 
  659.  */
  660. marksub(ldev, fatimg, fatsiz, clno)
  661. int  ldev;
  662. UWORD *fatimg;
  663. UWORD fatsiz;
  664. UWORD clno;
  665. {
  666.     UWORD *neworphs;        /* list of new orphans */
  667.     int  *lstneworphs();
  668.     FCB  *dirent;        /* a directory entry */
  669.     UWORD clus, nxtcl;        /* current and next cluster number */
  670.     int  act;            /* action requested by user */
  671.     char buf[512];
  672.     int  ret = OK;
  673.     
  674.     lmrksub[BADSUB].ob_width = strlen(dpname)*gl_wchar; 
  675.     lmrksub[BADSUB].ob_x 
  676.     = (lmrksub->ob_width - lmrksub[BADSUB].ob_width) >> 1;
  677.     lmrksub[BADSUB].ob_spec = dpname;
  678.     (lmrksub[SUBSEC].ob_spec)->te_ptext = sectbuf;
  679.     itoa(clno+2, clusbuf);
  680.     (lmrksub[SUBCLU].ob_spec)->te_ptext = clusbuf;
  681.     
  682.     lmrksub[SUBDELSV].ob_state = NORMAL;
  683.     lmrksub[SUBDELNS].ob_state = NORMAL;
  684.     lmrksub[SUBIGNOR].ob_state = NORMAL;
  685.     
  686.     /* Put up the dialogue */
  687.     switch ((act = execform(lmrksub))) {
  688.     case SUBIGNOR:            /* clicked on ignore */
  689.         ret = 0;
  690.         goto subend;
  691.     
  692.     case SUBDELSV:            /* clicked on delete and save */
  693.         ARROW_MOUSE;
  694.         if (form_alert(2, svfiles) == 2) {    /* bail out */
  695.         BEE_MOUSE;
  696.         ret = 0;
  697.         goto subend;
  698.         }
  699.         break;
  700.         
  701.     case SUBDELNS:            /* clicked on delete and not save */
  702.         ARROW_MOUSE;
  703.         if (form_alert(2, nsfiles) == 2) {    /* bail out */
  704.         BEE_MOUSE;
  705.         ret = 0;
  706.         goto subend;
  707.         }
  708.         break;
  709.         
  710.     default:
  711.         break;
  712.     }    
  713.  
  714.     /* Really removing subdirectory and mark bad sector */
  715.     BEE_MOUSE;
  716.     /* Read directory sector containing the subdirectory file from disk */
  717.     if ((ret = rdsects(ldev, 1, buf, (SECTOR)finfo->gs_dsect*ratio)) != 0) {
  718.         if (tsterr(ret) != OK)
  719.         err(sdirread);
  720.     ret = 0;
  721.     goto subend;
  722.     }
  723.  
  724.     /* Get directory entry of file */
  725.     dirent = (FCB *)(buf + finfo->gs_doff);
  726.     
  727.     /* Delete the subdirectory */
  728.     dirent->f_name[0] = FN_DEL;
  729.     
  730.     /* Write directory sector containing the subdirectory file back to disk */
  731.     if ((ret = wrsects(ldev,1,buf,(SECTOR)finfo->gs_dsect*ratio)) != 0) {
  732.         if (tsterr(ret) != OK)
  733.         err(sdirwrit);
  734.         ret = 0;
  735.     goto subend;
  736.     }
  737.  
  738.     /* Zero entries of the subdirectory file in FAT, and mark bad sector */
  739.                     /* start from beginning of file */
  740.     for (gw((UWORD *)&dirent->f_clust, &clus);
  741.          clus < 0xfff0;        /* until EOF or a cluster marked bad */
  742.          clus = nxtcl)        /* next cluster becomes current */
  743.     {
  744.          gw((UWORD *)(fatimg+clus), &nxtcl);  /* find where next cluster is */
  745.          *(fatimg+clus) = 0;             /* zero current cluster */
  746.     }
  747.     *(fatimg+clno+2) = 0xf7ff;        /* mark cluster with bad sector */
  748.     
  749.     /* Update FATs */
  750.     if ((ret = wrsects(ldev, fatsiz, (char *)fatimg, (SECTOR)ratio)) != 0 ||
  751.         (ret = wrsects(ldev,fatsiz,(char *)fatimg,(SECTOR)ratio+fatsiz)) != 0){
  752.         if (tsterr(ret) != OK)
  753.         err(fatwrite);
  754.     ret = ERROR;
  755.     goto subend;
  756.     }
  757.  
  758.     /* Find out list of orphans introduced by deleting the subdirectory */
  759.     if ((neworphs = lstneworphs(ldev)) < 0) {
  760.         ret = ERROR;        /* error occurs when finding new orphans */
  761.         goto subend;
  762.     } else if (!neworphs) {
  763.         ret = 1;        /* No new orphans! No files to recover! */
  764.         goto subend;
  765.     }
  766.  
  767.     /* Recover files in subdirectory and put them in root directory */
  768.     if (act == SUBDELSV) {    /* requested to recover file */
  769.     if (rcvrfiles(ldev, fatimg, fatsiz, neworphs) != OK) {
  770.         ret = ERROR;
  771.         goto subend;
  772.     }
  773.     } else if (act == SUBDELNS) {    /* requested not to recover file */
  774.         if (rmvfiles(fatimg, neworphs) != OK) {
  775.             ret = ERROR;
  776.             goto subend;
  777.     }
  778.     }
  779.     ret = 1;        /* everything is fine.  JUST FINE... */
  780. subend:
  781.     if (neworphs > 0L) Mfree((long)neworphs);
  782.     return ret;
  783. }
  784.  
  785.  
  786.  
  787.  
  788. /*
  789.  *  Lstneworphs()
  790.  *    Find out what orphans exist and record them in an orphan list.
  791.  *
  792.  *  Input:
  793.  *    ldev - logical device number ('C' -> 'P')
  794.  *
  795.  *  Return:
  796.  *    neworphs - list of new orphans
  797.  *    0 - if there is no new orphans
  798.  *    ERROR - if anything goes wrong
  799.  */
  800. int*
  801. lstneworphs(ldev)
  802. int ldev;
  803. {
  804.     UWORD *neworphs;    /* current orphans in FAT */
  805.     UWORD *orphans;    /* current orphans in FAT */
  806.     int numnew, i;
  807.     long ret;
  808.     
  809.     /* Check integrity of FATs, and find all orphans that exist */
  810.     if ((orphans = fatck(ldev-'A')) <= 0L) {
  811.     switch (orphans) {
  812.         case FFATS:
  813.         ret = err(fatread);
  814.         goto lstend;
  815.         case FROOT:
  816.         ret = err(dirread);
  817.         goto lstend;
  818.         case FFAIL:
  819.         ret = err(nomemory);
  820.         goto lstend;
  821.         case FAMBI:
  822.         ret = err(badfat);
  823.         goto lstend;
  824.         default:
  825.         break;
  826.     }
  827.     }
  828.  
  829.     ret = 0L;    /* assume there is no new orphans */
  830.     
  831.     /* Any orphans in FAT? */
  832.     if (*orphans > 0) {        /* Yes, try to recover them */
  833.     /* Allocate space for new orphans */
  834.     if ((neworphs =
  835.         (UWORD *)Malloc((long)((*orphans+1)<<1))) <= 0L) {
  836.         ret = err(nomemory);
  837.         goto lstend;
  838.         }
  839.         
  840.     for (i = 0; i <= *orphans; i++)
  841.         *(neworphs + i) = *(orphans + i);
  842.         
  843.     ret = neworphs;
  844.     }
  845. lstend:
  846.     return ret;
  847. }
  848.  
  849.  
  850. /*
  851.  *  Rcvrfiles()
  852.  *    Recover files of a trashed subdirectory.  The files will
  853.  *  become temporary files in the root directory of the partition.
  854.  *  Their names will be tmpnnnn, where nnnn is a four digit hex
  855.  *  number which is the starting cluster number of that file.
  856.  *
  857.  *  Input:
  858.  *    ldev - logical device number. ('C' -> 'P')
  859.  *    fatimg  - image of FAT 0.
  860.  *    fatsiz - number of clusters FAT occupies.
  861.  *    neworphs - list of new orphans.
  862.  *
  863.  *  Output:
  864.  *    OK - recover (if necessary) is successful.
  865.  *    ERROR - something is wrong.
  866.  *
  867.  *  Comments:
  868.  *    To recover the new lost files, we construct a temporary FAT
  869.  *  which contains only the newly introduced orphans (excluding clusters
  870.  *  marked bad and reserved; that is, only if they are part of a file). 
  871.  *  All other entries are 0's.  We then walk through the FAT to find the
  872.  *  first non-zero entry, and call getstart() to find out where the head
  873.  *  of this chain is.  This chain will then be saved as a temp file in the
  874.  *  root directory, named tmpnnnn (nnnn is the starting cluster number of
  875.  *  the chain in hex).  To save the temp file in the root directory, we
  876.  *  have to search for an empty slot in the root and enter information of
  877.  *  the temp file into the directory entry.  After a chain is recovered,
  878.  *  zero out the chain in the temporary FAT and start to look for the next
  879.  *  non-zero entry in it for the next chain, until all chains are recovered.
  880.  *    Note that the content of the temporary FAT (referred to as fakefat)
  881.  *  is in regular 68000 word format.  The entries are _NOT_ in 8086 byte-
  882.  *  swapped format.
  883.  */    
  884. rcvrfiles(ldev, fatimg, fatsiz, neworphs)
  885. int ldev;
  886. UWORD *fatimg;
  887. UWORD fatsiz;
  888. UWORD *neworphs;
  889. {
  890.     FCB *rootdir, *availslot;    /* root directory; available slot */
  891.     GSINFO *chain;        /* info of an orphan chain of clusters */
  892.     UWORD *fakefat;        /* a temp fat image */
  893.     UWORD content;        /* cluster pointed to by a FAT entry */
  894.     UWORD orph2del;        /* number of orphan yet to be deleted */
  895.     UWORD i;            /* index into orphan list */
  896.     UWORD orph;            /* an orphan in fake FAT */
  897.     UWORD stfat;        /* index into fake FAT */
  898.     UWORD stdir;        /* index into root directory */
  899.     UWORD dirslot;        /* empty directory slot number */
  900.     UWORD numclus;        /* number of clusters file used */
  901.     UWORD prev, curr;        /* previous and current cluster number */
  902.     int done;            /* 1: finish recovering files */
  903.     int endofchain;        /* 1: reached end of file chain */
  904.     int rootfull;        /* root directory is full */
  905.     int tget;            /* current time or date */
  906.     int ret;            /* return code */
  907.     char namebuf[10];
  908.     
  909.     
  910.     /* Allocate space for root directory */
  911.     rootdir = 0L;
  912.     if ((rootdir = (FCB *)mymalloc(sectdir << 9)) <= 0L) {
  913.         ret = err(nomemory);
  914.         goto rcvrend;
  915.     }
  916.     
  917.     /* Read in root directory */
  918.     if ((ret = rdsects(ldev, sectdir, (char *)rootdir, strootdir)) != 0) {
  919.         if (tsterr(ret) != OK)
  920.             err(dirread);
  921.         ret = ERROR;
  922.         goto rcvrend;
  923.     }
  924.  
  925.     /* Allocate space for a temporary FAT image and zero it out */
  926.     fakefat = 0L;
  927.     if ((fakefat = (UWORD *)Malloc((long)fatsiz << 9)) <= 0L) {
  928.         ret = err(nomemory);
  929.         goto rcvrend;
  930.     }
  931.     fillbuf((char *)fakefat, ((long)fatsiz << 9), 0L);
  932.     
  933.     /* Copy the new orphans from current FAT to this       */
  934.     /* temporary FAT only if they are part of a file chain */
  935.     orph2del = 0;        /* no orphan is copied to fake FAT yet */
  936.     for (i = 1; i <= *neworphs; i++) {
  937.         gw((fatimg + *(neworphs + i)), &content);
  938.         if ((content >= 0x0002 && content <= 0x7fff)    /* part of file */
  939.             || (content >= 0xfff8 && content <= 0xffff)) {
  940.             *(fakefat + *(neworphs + i)) = content;    /* copy to temp FAT */
  941.             orph2del++;        /* one more orphan to take care of */
  942.         }
  943.     }
  944.  
  945.     /* start recovering... */
  946.     stfat = 2;            /* start at beginning of fake FAT */
  947.     stdir = 0;            /* start at beginning of root directory */
  948.     endofdir = FALSE;        /* not at end of root directory yet */
  949.     rootfull = 0;
  950.     
  951. nextorph:
  952.     while (orph2del > 0) {    /* more orphan to take care of? */
  953.         /* Yes, find next non-zero entry in fake FAT */
  954.         for (orph = stfat; *(fakefat+orph) == 0; orph++)
  955.             ;
  956.         stfat = orph + 1;    /* next time start from here to walk FAT */
  957.  
  958.     /* Root directory was already full, and user choose to 
  959.        deallocate all remaining new orphans on the disk.   */
  960.     if (rootfull) {            /* root directory is full already */
  961.         *(fatimg + orph) = 0;    /* deallocate orphan from real FAT */
  962.         orph2del--;            /* one fewer to go */
  963.         goto nextorph;        /* find the next one */
  964.     }
  965.     
  966.     /* Find an empty slot in the root directory */
  967.     if ((dirslot = rtdirslot(rootdir, stdir)) == ERROR) {
  968.         /* FIRST TIME -- Root directory is FULL! */
  969.         rootfull = 1;
  970.         if (execform(nodrslot) == NODRNO) {       /* wanna keep lost clus */
  971.             goto okend;               /* Nope! */
  972.         }
  973.         /* Yup. */
  974.         *(fatimg + orph) = 0;    /* Zero out current orphan */
  975.         orph2del--;            /* one fewer to go */
  976.         goto nextorph;        /* find the next one to zero out */
  977.     }
  978.     stdir = dirslot + 1; /* next time start from here to find slots */
  979.  
  980.     /* Find head of chain that this cluster belongs to */        
  981.     if ((chain = getstart(&emptyorph, orph, ldev-'A')) <= 0L) {
  982.         ret = ERROR;
  983.         goto rcvrend;
  984.     }
  985.  
  986.     /* Erase chain from fake FAT */
  987.     endofchain = 0;                /* not end of chain yet */
  988.     numclus = 0;                /* no cluster zeroed yet */
  989.     prev = curr = chain->gs_head;        /* start from head of chain */
  990.     
  991.     while (!endofchain) {            /* while not end of chain */
  992.         content = *(fakefat + curr);    /* next cluster in chain */
  993.         *(fakefat + curr) = 0;        /* zero current entry */
  994.         if (!content) {            /* next cluster is 0? */
  995.             endofchain = 1;            /* Yes, BAD! end it */
  996.             *(fatimg + prev) = 0xffff;    /* stop chain in real FAT */
  997.         } else if (content >= 0xfff8 && content <= 0xffff) { /* last clus */
  998.             numclus++;            /* zeroed last one */
  999.         endofchain = 1;            /* end of chain reached */
  1000.         } else {                /* still at middle of chain */
  1001.             prev = curr;            /* current becomes previous */
  1002.         curr = content;            /* next becomes current */
  1003.         numclus++;            /* one more is zeroed */
  1004.         }
  1005.     }
  1006.     
  1007.     /* Move the file to root directory and erase chain from fake FAT */
  1008.     availslot = rootdir + dirslot;
  1009.     strcpy(availslot->f_name, "TMP");          /* file name */
  1010.     htoa((long)chain->gs_head, namebuf, 1);
  1011.     strcat(availslot->f_name, namebuf);
  1012.     strcat(availslot->f_name, "    ");
  1013.     availslot->f_attrib = 0;              /* file attrib */
  1014.     tget = Tgettime();                  /* time created */
  1015.     iw(&(availslot->f_time), tget);
  1016.     tget = Tgetdate();                  /* date created */
  1017.     iw(&(availslot->f_date), tget);
  1018.     iw(&(availslot->f_clust), chain->gs_head);      /* starting clus */
  1019.     il(&(availslot->f_fileln), (long)(numclus*clusiz));  /* file length */
  1020.     
  1021.     /* update number of orphans to delete */
  1022.     orph2del -= numclus;
  1023.     }
  1024.  
  1025. okend:
  1026.     /* Write root directory back on disk */
  1027.     if ((ret = wrsects(ldev, sectdir, (char *)rootdir, strootdir)) != 0) {
  1028.         if (tsterr(ret) != OK)
  1029.               err(dirwrite);
  1030.           ret = ERROR;
  1031.         goto rcvrend;
  1032.     }
  1033.     ret = OK;
  1034. rcvrend:
  1035.     if (fakefat > 0) Mfree((long)fakefat);
  1036.     if (rootdir > 0) free (rootdir);
  1037.     return ret;
  1038. }
  1039.  
  1040.  
  1041. /*
  1042.  *  Rtdirslot()
  1043.  *    Find the next available directory slot in the root directory
  1044.  *  of the given partition.
  1045.  *
  1046.  *  Input:
  1047.  *    dirimg - image of the root directory read from disk.
  1048.  *    start - directory slot number to start with.
  1049.  *
  1050.  *  Return:
  1051.  *    dirslot - available directory slot number.
  1052.  *    ERROR - no more available slot.
  1053.  *
  1054.  *  Comments:
  1055.  *    Note that, a zero entry marks the end of the directory.  That is,
  1056.  *  all subsequent entries are available.
  1057.  */
  1058. rtdirslot(dirimg, start)
  1059. FCB *dirimg;
  1060. UWORD start;
  1061. {
  1062.     int i;
  1063.     
  1064.     if (endofdir == TRUE) {        /* End of directory reached? */
  1065.         if (start < ndirs)        /* Yes, full? */
  1066.             return (start);        /* No, next slot will be available. */
  1067.         else                 /* Yes, no available slot */
  1068.             return ERROR;
  1069.     }
  1070.         
  1071.     for (i = start; i < ndirs; i++) {
  1072.         if ((dirimg+i)->f_name[0] == FN_DEL) /* entry of a deleted file is OK */
  1073.             return i;
  1074.         if (!((dirimg + i)->f_name[0])) {    /* end of directory is reached */
  1075.             endofdir = TRUE;
  1076.             return i;
  1077.         }
  1078.     }
  1079.     return ERROR;    /* no available slot found */
  1080. }
  1081.  
  1082.  
  1083. /*
  1084.  *  Rmvfiles()
  1085.  *    Remove orphan clusters which were allocated to files which
  1086.  *  are now lost from the FAT.
  1087.  *
  1088.  *  Input:
  1089.  *    fatimg  - image of FAT 0.
  1090.  *    neworphs - list of new orphans.
  1091.  *
  1092.  *  Return:
  1093.  *    OK - when finished.
  1094.  */
  1095. rmvfiles(fatimg, neworphs)
  1096. UWORD *fatimg;
  1097. UWORD *neworphs;
  1098. {
  1099.     int i;        /* index into orphan list */
  1100.     UWORD content;    /* pointer to next cluster */
  1101.     
  1102.     for (i = 1; i <= *neworphs; i++) {
  1103.         gw((fatimg + *(neworphs + i)), &content);
  1104.         if ((content >= 0x0002 && content <= 0x7fff)    /* part of file */
  1105.             || (content >= 0xfff8 && content <= 0xffff)) {
  1106.         *(fatimg + *(neworphs + i)) = 0;        /* remove it */
  1107.     }
  1108.     }
  1109.     return OK;
  1110. }
  1111.  
  1112. /*
  1113.  *  Markfile()
  1114.  *    Put up dialogue informing which file is trashed, and
  1115.  *  request action from user.
  1116.  *
  1117.  *  Input:
  1118.  *    ldev  - logical device number. ('C' -> 'P')
  1119.  *    fatimg  - image of FAT 0.
  1120.  *    fatsiz - number of clusters FAT occupies.
  1121.  *    clno - cluster which bad sector resides.
  1122.  *    nxtcl    - cluster pointed to by bad cluster.
  1123.  *
  1124.  *  Return:
  1125.  *    1 - if successful and cluster with bad sector is marked.
  1126.  *    0 - if successful but didn't mark the bad sector.
  1127.  *    ERROR - something's wrong.
  1128.  */
  1129. markfile(ldev, fatimg, fatsiz, clno, nxtcl)
  1130. int  ldev;
  1131. UWORD *fatimg;
  1132. UWORD fatsiz;
  1133. UWORD clno;
  1134. UWORD nxtcl;
  1135. {
  1136.     int  ret;
  1137.  
  1138.     lmrkfile[BADFILE].ob_width = strlen(dpname)*gl_wchar; 
  1139.     lmrkfile[BADFILE].ob_x 
  1140.     = (lmrkfile->ob_width - lmrkfile[BADFILE].ob_width) >> 1;
  1141.     lmrkfile[BADFILE].ob_spec = dpname;
  1142.     (lmrkfile[BADSEC].ob_spec)->te_ptext = sectbuf;
  1143.     itoa(clno+2, clusbuf);    
  1144.     (lmrkfile[BADCLU].ob_spec)->te_ptext = clusbuf;
  1145.     lmrkfile[DELFILE].ob_state = NORMAL;
  1146.     lmrkfile[SKIPOVER].ob_state = NORMAL;
  1147.     lmrkfile[IGNORBAD].ob_state = NORMAL;
  1148.  
  1149.     /* Put up the dialogue */
  1150.     ret = execform(lmrkfile);
  1151.  
  1152.     /* Action requested by Jackson is... */
  1153.     switch (ret) {
  1154.     case DELFILE:    /* Delete file */
  1155.         /* User's choice => can delete */
  1156.         if (Fdelete(pname)) {
  1157.         ret = err(cantdel);
  1158.         }
  1159.            
  1160.         /* Read current FAT; fat0 starts at sector 1 */
  1161.         if ((ret = rdsects(ldev, fatsiz, (char *)fatimg, (SECTOR)ratio)) != 0) {
  1162.             if (tsterr(ret) != OK)
  1163.             err(fatread);
  1164.         ret = ERROR;
  1165.         break;
  1166.         }
  1167.         
  1168.         /* Mark the cluster bad */
  1169.         *(fatimg+clno+2) = 0xf7ff;    /* 0xfff7 in 8086-land */
  1170.         ret = 1;    /* 1 cluster marked bad */
  1171.         break;
  1172.  
  1173.     case SKIPOVER:    /* Skip over bad sector */
  1174.         ret = skpfile(ldev, fatimg, fatsiz, clno, nxtcl);
  1175.         break;
  1176.  
  1177.     case IGNORBAD:
  1178.         ret = 0;
  1179.         break;
  1180.     
  1181.     default:
  1182.         ret = ERROR;
  1183.         break;
  1184.     }
  1185.     return ret;
  1186. }
  1187.  
  1188.  
  1189. /*
  1190.  *  Skpfile()
  1191.  *    Skip over a cluster which contains a bad sector of a file.
  1192.  *
  1193.  *  Input:
  1194.  *    ldev  - logical device number. ('C' -> 'P')
  1195.  *    fatimg  - image of FAT 0.
  1196.  *    fatsiz - number of clusters FAT occupies.
  1197.  *    clno - cluster which bad sector resides.
  1198.  *    nxtcl    - cluster pointed to by bad cluster.
  1199.  *
  1200.  *  Return:
  1201.  *    1 - if cluster with bad sector is marked.
  1202.  *    OK - if successful.
  1203.  *    ERROR - can't read boot sector.
  1204.  *
  1205.  *  Comments:
  1206.  *    Need to adjust length and/or modify directory entry of the
  1207.  *  corresponding file.
  1208.  *    Complications arise when file is a subdirectory.  For first
  1209.  *  trial, nothing is done for subdirectories for now.
  1210.  *
  1211.  */
  1212. skpfile(ldev, fatimg, fatsiz, clno, nxtcl)
  1213. int  ldev;
  1214. UWORD *fatimg;
  1215. UWORD fatsiz;
  1216. UWORD clno;
  1217. UWORD nxtcl;
  1218. {
  1219.     FCB  *dirent;        /* a directory entry */
  1220.     int  ret;            /* return code */
  1221.     long flen;            /* file length (68000 format) */
  1222.     long gl();            /* get a long from 8086 format */
  1223.     long left;            /* #bytes in last cluster of file */
  1224.     char buf[512];
  1225.     
  1226.     ret = OK;    /* assume everything is OK now... */
  1227.  
  1228.     /* Read directory sector containing the file from disk */
  1229.     if ((ret = rdsects(ldev, 1, buf, (SECTOR)finfo->gs_dsect*ratio)) != 0) {
  1230.         if (tsterr(ret) != OK)
  1231.         err(sdirread);
  1232.     ret = 0;
  1233.     goto skipend;
  1234.     }
  1235.  
  1236.     /* Get directory entry of file */
  1237.     dirent = (FCB *)(buf + finfo->gs_doff);
  1238.  
  1239.     /* Relink the file */
  1240.     if (!(finfo->gs_count - 1)) {    /* it's 1st cluster */
  1241.         if (nxtcl >= 0xfff0) {        /* it's also last cluster */
  1242.             if (Fdelete(pname))        /* just delete it */
  1243.                 ret = err(cantdel);
  1244.                 
  1245.             /* Read in current FAT; fat0 starts at sector 1 */
  1246.             if ((ret = rdsects(ldev,fatsiz,(char *)fatimg,(SECTOR)ratio))!= 0){
  1247.                 if (tsterr(ret) != OK)
  1248.                     err(fatread);
  1249.                 ret = ERROR;
  1250.                 goto skipend;
  1251.             }
  1252.         goto markit;
  1253.         }
  1254.     iw(&(dirent->f_clust), nxtcl);    /* new starting clus = next clus */
  1255.     } else {            /* otherwise */
  1256.     iw((fatimg + finfo->gs_prev), nxtcl);  /* skip cluster marked bad */
  1257.     }
  1258.  
  1259.     /* Adjust file size */
  1260.     /* Is it end of file, or #bytes give exact clusters?? */
  1261.     gl(&(dirent->f_fileln), &flen);
  1262.     if (flen) {
  1263.     if ((!(left = flen % clusiz)) || nxtcl < 0xfff0)
  1264.         flen -= clusiz;    /* Yes, subtract entire unusable cluster */
  1265.     else
  1266.         flen -= left;    /* Nope, subtract unusable bytes */
  1267.     
  1268.     il(&(dirent->f_fileln), flen);    /* install new file length */
  1269.     }
  1270.  
  1271.     /* Write directory sector containing the file back to disk */
  1272.     if ((ret = wrsects(ldev, 1, buf, (SECTOR)finfo->gs_dsect*ratio)) != 0) {
  1273.         if (tsterr(ret) != OK)
  1274.         err(sdirwrit);
  1275.     ret = 0;
  1276.     goto skipend;
  1277.     }
  1278. markit:    
  1279.     /* Mark the cluster bad */
  1280.     *(fatimg+clno+2) = 0xf7ff;    /* 0xfff7 in 8086-land */
  1281.     ret = 1;    /* 1 cluster marked bad */
  1282. skipend:
  1283.     return (ret);
  1284. }
  1285.  
  1286.  
  1287. /*
  1288.  * Put long in memory in 8086 byte-reversed format.
  1289.  *
  1290.  */
  1291. il(d, s)
  1292. long *d;
  1293. long s;
  1294. {
  1295.     char *p;
  1296.  
  1297.     p = (char *)d;
  1298.     p[0] = s & 0xffff;
  1299.     p[1] = ((s >> 8) & 0xffff);
  1300.     p[2] = ((s >> 16) & 0xffff);
  1301.     p[3] = ((s >> 24) & 0xffff);
  1302. }
  1303.  
  1304.  
  1305. /*
  1306.  * Get word in memory, from 8086 byte-reversed format.
  1307.  *
  1308.  */
  1309. long gl(s, d)
  1310. long *s;
  1311. long *d;
  1312. {
  1313.     char *p, *q;
  1314.  
  1315.     p = (char *)s;
  1316.     q = (char *)d;
  1317.     q[0] = p[3];
  1318.     q[1] = p[2];
  1319.     q[2] = p[1];
  1320.     q[3] = p[0];
  1321.     return *d;
  1322. }
  1323.  
  1324. /*
  1325.  * fl() - Find a long in an array of longs.
  1326.  *    - Returns 1 if found; 0 if not found;
  1327.  */
  1328. fl(tofind, numl, llist)
  1329. long    tofind;        /* long to search for */
  1330. UWORD    numl;        /* # of longs in the array */
  1331. long    *llist;        /* ptr to array of longs */
  1332. {
  1333.     long    i, *slist;
  1334.     
  1335.     slist = llist;
  1336.     for (i = 0L; i < numl; i++)
  1337.     if (tofind == *slist++)
  1338.         return 1;
  1339.         
  1340.     return 0;
  1341. }
  1342.